/*
 
 TopMind jLynx "jLynx JDBC Framework"
 Copyright (c) 2004-2007. TopMind Systems Inc.
 All rights reserved.
 
 This file is part of TopMind jLynx.
 
 TopMind jLynx is free software; you can redistribute it and/or modify
 it under the terms of the License. See website for License.
 
 */
package net.sf.jlynx;

import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * Class to create instances of <code>Relational</code>.
 * </p>
 * 
 * <p>
 * The overloaded getInstance() methods can accept an instance or class of a
 * JavaBean, aka POJO, that will contain the data to be persisted or retrieved
 * from a database.
 * </p>
 * 
 * $Id: RelationalFactory.java 99 2007-06-21 02:51:13Z gritc11 $
 * 
 */
public final class RelationalFactory {

	private static Logger logger = LoggerFactory
			.getLogger(RelationalFactory.class);

	private static final long serialVersionUID = 1023629289046753049L;

	private static boolean isXml = true;

	static {
		// triggers parser to parse jlynx.xml
		ConfigParser cp = new ConfigParser();
		isXml = ConfigParser.isParsed;
		logger.info(cp.getClass().getCanonicalName()
				+ " :: using XML config ? " + isXml);
	}

	/**
	 * <p>
	 * Creates a <code>Relational</code> instance using 'default' connection,
	 * using an empty Map instead of a POJO. To override the empty Map use the
	 * <code>Relational.setObject()</code> method.
	 * </p>
	 * 
	 */
	public static Relational getInstance() {
		return getInstance(new TreeMap(), ConfigParser.DEFAULT);
	}

	/**
	 * <p>
	 * Creates <code>Relational</code> instance using 'default' connection.
	 * Use this create method when you do not need a populated POJO to start.
	 * </p>
	 * 
	 * @param cls
	 *            class of JavaBean-like object
	 * @return Relational
	 */
	public static Relational getInstance(Class cls) {
		String c = cls.getName();
		Object o = null;
		try {
			Class.forName(c);
			o = cls.newInstance();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return getInstance(o);
	}

	/**
	 * <p>
	 * Creates <code>Relational</code> instance using 'named' connection. Use
	 * this create method when you do not need a populated POJO to start.
	 * </p>
	 * 
	 * @param cls
	 *            class of JavaBean-like object
	 * @return Relational
	 */
	public static Relational getInstance(Class cls, String namedConnection) {
		String c = cls.getName();
		Object o = null;
		try {
			Class.forName(c);
			o = cls.newInstance();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return getInstance(o, namedConnection);
	}

	/**
	 * <p>
	 * Creates <code>Relational</code> instance using 'default' connection.
	 * </p>
	 * 
	 * <p>
	 * If POJO is instance of Application.class, table name must be APPLICATION,
	 * unless configured in XML to be something else...<br>
	 * <br>
	 * <code>&lt;entity class='my.pkg.ApplicationBean' name='APPLICATION' /&gt;</code>
	 * </p>
	 * 
	 * <p>
	 * Database connection is <i>default</i> connection from XML.
	 * </p>
	 * 
	 * @param pojo
	 *            POJO
	 * @return Relational
	 */
	public static Relational getInstance(Object pojo) {
		return getInstance(pojo, ConfigParser.DEFAULT);
	}

	/**
	 * Creates <code>Relational</code> instance using a named connection from
	 * XML configuration (jlynx.xml).
	 * 
	 * @param pojo
	 *            any JavaBean-like object
	 * @param namedConnection
	 *            name of connection as configured in XML
	 * @return Relational
	 */
	public static Relational getInstance(Object pojo, String namedConnection) {

		String entity = null;

		if (namedConnection == null)
			namedConnection = ConfigParser.DEFAULT;
		else
			namedConnection = namedConnection.trim().toLowerCase();

		ConnectionBean cb = (ConnectionBean) ConfigParser.getConnectionDefs()
				.get(namedConnection);

		try {
			entity = (String) cb.getMappings().get(pojo.getClass().getName());
			if (entity == null)
				throw new NullPointerException();// bug fix v1.3.4

		} catch (NullPointerException e) {

			// no mapping - default condition (reflection)
			entity = pojo.getClass().getName().toUpperCase();

			if (entity.indexOf(".") != -1)
				entity = entity.substring(entity.lastIndexOf(".") + 1);

		}

		RelationalImpl r = new RelationalImpl(entity, cb);

		if (pojo instanceof Class) {

			try {
				pojo = ((Class) pojo).newInstance();
			} catch (IllegalAccessException ex) {
				ex.printStackTrace();
			} catch (InstantiationException ex) {
				ex.printStackTrace();
			}
		}

		r.refresh(pojo);

		logger.debug("Creating instance of " + Relational.class.getName());
		if (cb != null)
			logger.debug("Using connection name: \"" + cb.getName()
					+ "\" from jlynx.xml");
		logger.debug("Using object of type: " + pojo.getClass().getName());
		logger.debug("Current DB entity is: \"" + entity + "\"");
		logger.debug("Switch DB entity using Relational#setEntity(String)");

		return (Relational) r;

	}

	/**
	 * <p>
	 * Creates a <code>Relational</code> instance using parameter named
	 * connection, using an empty Map instead of a POJO. To override the empty
	 * Map use the <code>Relational.setObject()</code> method.
	 * </p>
	 * 
	 */
	public static Relational getInstance(String namedConnection) {
		return getInstance(new TreeMap(), namedConnection);
	}

	private RelationalFactory() {
	}

}